package testing;
/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
//package je3.nio;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;

public class ChannelToWriter {
	/**
	 * Read bytes from the specified channel, decode them using the specified
	 * Charset, and write the resulting characters to the specified writer
	 */
	public static void copy(ReadableByteChannel channel, Writer writer,
			Charset charset) throws IOException {
		// Get and configure the CharsetDecoder we'll use
		CharsetDecoder decoder = charset.newDecoder();
		decoder.onMalformedInput(CodingErrorAction.IGNORE);
		decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);

		// Get the buffers we'll use, and the backing array for the CharBuffer.
		ByteBuffer bytes = ByteBuffer.allocateDirect(2 * 1024);
		CharBuffer chars = CharBuffer.allocate(2 * 1024);
		char[] array = chars.array();

		while (channel.read(bytes) != -1) { // Read from channel until EOF
			bytes.flip(); // Switch to drain mode for decoding
			// Decode the byte buffer into the char buffer.
			// Pass false to indicate that we're not done.
			decoder.decode(bytes, chars, false);

			// Put the char buffer into drain mode, and write its contents
			// to the Writer, reading them from the backing array.
			chars.flip();
			writer.write(array, chars.position(), chars.remaining());

			// Discard all bytes we decoded, and put the byte buffer back into
			// fill mode. Since all characters were output, clear that buffer.
			bytes.compact(); // Discard decoded bytes
			chars.clear(); // Clear the character buffer
		}

		// At this point there may still be some bytes in the buffer to decode
		// So put the buffer into drain mode call decode() a final time, and
		// finish with a flush().
		bytes.flip();
		decoder.decode(bytes, chars, true); // True means final call
		decoder.flush(chars); // Flush any buffered chars
		// Write these final chars (if any) to the writer.
		chars.flip();
		writer.write(array, chars.position(), chars.remaining());
		writer.flush();
	}

	// A test method: copy a UTF-8 file to standard out
	public static void main(String[] args) throws IOException {
		FileChannel c = new FileInputStream("new file").getChannel();
		OutputStreamWriter w = new OutputStreamWriter(System.out);
		Charset utf8 = Charset.forName("UTF-8");
		ChannelToWriter.copy(c, w, utf8);
		c.close();
		w.close();
	}
}